#include "StdAfx.h"

#include "ProjectDefines.h"
#if defined(MAP_LOADING_SLICING)

#include "SyncLock.h"

#ifdef LINUX
#include <semaphore.h>
#endif

SSyncLock::SSyncLock(const char* name, int id, bool own)
{
	stack_string ss;
	ss.Format("%s_%d",name, id);

	Open(ss);
	if(own)
	{
		if(!IsValid())
		{
			Create(ss);
			number = id;
		}
		else
		{
			Close();
		}
	}
	else
		number = id;
}

SSyncLock::SSyncLock(const char* name, int minId, int maxId)
{
	ev = 0;
	stack_string ss;
	for(int i=minId; i<maxId; ++i)
	{
		ss.Format("%s_%d",name, i);
		if(Open(ss))
		{
			Close();
			continue;
		}
		if(Create(ss))
			number = i;
		break;
	}
}

SSyncLock::~SSyncLock()
{
	Close();
}

void SSyncLock::Own(const char* name)
{
	o_name.Format("%s_%d", name, number);
}

#ifdef LINUX

bool SSyncLock::Open(const char* name)
{
	ev = sem_open(name, 0);
	if(ev)
		CryLogAlways("Opened %p %s", ev, name);
	return IsValid();
}

bool SSyncLock::Create(const char* name)
{
	ev = sem_open(name, O_CREAT|O_EXCL, 0777, 0);
	if(ev)
	{
		CryLogAlways("Created event %p %s", ev, name);
		o_name = name;
	}
	else
		CryLogAlways("Failed to create event %s %d", name, errno);
	return IsValid();
}

void SSyncLock::Signal()
{
	if(ev)
		sem_post(ev);
}

bool SSyncLock::Wait(int ms)
{
	if(!ev)
		return false;

	timespec t;
	clock_gettime(CLOCK_REALTIME, &t);

	static const int NANOSECS_IN_MSEC = 1000000;
	static const int NANOSECS_IN_SEC = 1000000000;

	t.tv_sec += ms/1000;
	t.tv_nsec += (ms%1000)*NANOSECS_IN_MSEC;
	if(t.tv_nsec > NANOSECS_IN_SEC)
	{
		t.tv_nsec -= NANOSECS_IN_SEC;
		++t.tv_sec;
	}	
	return sem_timedwait(ev, &t) == 0; //ETIMEDOUT for timeout
}

void SSyncLock::Close()
{
	if(ev)
	{
		CryLogAlways("Closed event %p", ev);
		if(!o_name.empty())
			sem_unlink(o_name);
		sem_close(ev);
		ev = 0;
	}
}
#else
bool SSyncLock::Open(const char* name)
{
	ev = OpenEvent(SYNCHRONIZE, FALSE, name);
	if(ev)
		CryLogAlways("Opened %p %s", ev, name);
	return IsValid();
}

bool SSyncLock::Create(const char* name)
{
	ev = CreateEvent(NULL, FALSE, FALSE, name);
	CryLogAlways("Created event %p %s", ev, name);
	return IsValid();
}

bool SSyncLock::Wait(int ms)
{
	//	CryLogAlways("Waiting %p", ev);
	DWORD res = WaitForSingleObject(ev, ms);
	if(res != WAIT_OBJECT_0)
	{
		CryLogAlways("WFS result %d", res);
	}
	return  res == WAIT_OBJECT_0;
}

void SSyncLock::Signal()
{
	//CryLogAlways("Signaled %p", ev);
	if(!SetEvent(ev))
	{
		CryLogAlways("Error signalling!");
	}
}

void SSyncLock::Close()
{
	if(ev)
	{
		CryLogAlways("Closed event %p", ev);
		CloseHandle(ev);
		ev = 0;
	}
}

#endif

bool SSyncLock::IsValid() const
{
	return ev != 0;
}

#endif // defined(MAP_LOADING_SLICING)
